﻿#region 文件信息

/*----------------------------------------------------------------
//
// 文件名称：
// 文件功能描述：
// 设计要求：
//
// 文 件 名：    VampirewalBootStartUp
// 创建者：      杨程
// 创建日期：	    2022/12/14 17:31:29

//----------------------------------------------------------------*/

#endregion

using System.Reflection;

namespace Vampirewal.Core.Components;

/// <summary>
/// 引导启动基类
/// </summary>
public interface IVampirewalBootStartUp
{
    /// <summary>
    /// 构建BootStartUp并启动
    /// </summary>
    void BuildBootStartUp(string[] args);
}

/// <summary>
/// 模块引导启动类
/// </summary>
public interface IVampirewalModuleBootStartup
{
    /// <summary>
    /// 模块名称
    /// </summary>
    string ModuleName { get; }

    /// <summary>
    /// 构建ModuleBootStartUp并启动
    /// </summary>
    /// <param name="services">IOC容器</param>
    void BuildModuleBootStartUp(IServiceCollection services);

    /// <summary>
    /// 模块启动
    /// </summary>
    void OnModuleRun(IServiceProvider service);

    /// <summary>
    /// 读取模块配置文件
    /// </summary>
    /// <param name="options"></param>
    void LoadModuleOption(IVampirewalCoreAppConfig config);


}

/// <summary>
/// 引导启动基类
/// </summary>
public abstract class VampirewalBootStartUp : IVampirewalBootStartUp
{
    /// <summary>
    /// 
    /// </summary>
    public VampirewalBootStartUp()
    {
        Collection = new ServiceCollection();
    }

    /// <summary>
    /// 容器
    /// </summary>
    protected IServiceProvider Services { get; private set; }

    /// <summary>
    /// 服务集合
    /// </summary>
    protected IServiceCollection Collection { get; private set; }

    /// <summary>
    /// 扫描并注册View和ViewModel
    /// </summary>
    /// <param name="services"></param>
    /// <exception cref="BootStartUpException"></exception>
    protected void RegisterAll(IServiceCollection services)
    {
        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(w => w.GetCustomAttribute<VampirewalIoCRegisterAttribute>() != null).ToArray();

        foreach (var item in types)
        {
            var Attribute = item.GetCustomAttribute<VampirewalIoCRegisterAttribute>();

            if (Attribute != null)
            {
                if (Attribute.Type == ClassType.Normal)
                {
                    if (VampirewalCoreContext.GetInstance().AddViewAndVMDic(Attribute.Token, item))
                    {
                        switch (Attribute.RegisterType)
                        {
                            case RegisterType.Singleton:
                                services.TryAddSingleton(item);
                                break;

                            case RegisterType.Transient:
                                services.TryAddTransient(item);
                                break;

                            case RegisterType.Scoped:
                                services.TryAddScoped(item);
                                break;
                        }
                    }
                    else
                    {
                        throw new BootStartUpException("重复Token");
                    }
                }
                else if (Attribute.InterfaceType != null && Attribute.Type == ClassType.Service)
                {
                    switch (Attribute.RegisterType)
                    {
                        case RegisterType.Singleton:
                            services.TryAddSingleton(Attribute.InterfaceType, item);
                            break;

                        case RegisterType.Transient:
                            services.TryAddTransient(Attribute.InterfaceType, item);
                            break;

                        case RegisterType.Scoped:
                            services.TryAddScoped(Attribute.InterfaceType, item);
                            break;
                    }
                }
                else if (Attribute.Type == ClassType.NormalOnlyToIOC)
                {
                    switch (Attribute.RegisterType)
                    {
                        case RegisterType.Singleton:
                            services.TryAddSingleton(item);
                            break;

                        case RegisterType.Transient:
                            services.TryAddTransient(item);
                            break;

                        case RegisterType.Scoped:
                            services.TryAddScoped(item);
                            break;
                    }
                }

            }
        }
    }

    /// <summary>
    /// 注册服务
    /// </summary>
    /// <param name="services"></param>
    protected abstract void RegisterService(IServiceCollection services);

    /// <summary>
    /// 启动参数
    /// </summary>
    protected virtual void GetStartArgs(string[] args)
    {

    }

    /// <summary>
    /// 是否已启动
    /// </summary>
    protected bool IsStart { get; set; } = false;

    /// <summary>
    /// 构建BootStartUp并启动
    /// </summary>
    public virtual void BuildBootStartUp(string[] args)
    {
        if (IsStart)
        {
            throw new BootStartUpException("请勿重复调用！");
        }

        GetStartArgs(args);

        RegisterAll(Collection);
        RegisterService(Collection);
        BuildModule();


        Services = Collection.BuildServiceProvider();

        VampirewalCoreContext.GetInstance().SetService(Services);
        SetBuildModuleServiceProvider();

        WindowsManager.GetInstance().OpenWindow(FirstViewKey, IsMainWindow: true);

        IsStart = true;
    }

    /// <summary>
    /// 初始窗体的ViewKey
    /// <para><typeparamref name="特性VampirewalIoCRegister中的token"/></para>
    /// </summary>
    protected abstract string FirstViewKey { get; }

    /// <summary>
    /// 继承的子类调用设置容器
    /// </summary>
    /// <param name="service"></param>
    protected void SetServiceProvider(IServiceProvider service)
    {
        Services = service;
    }

    #region 启动/关闭
    /// <summary>
    /// 当程序启动时
    /// <para>-------------------------------------</para>
    /// <para>★★★<paramref name="框架使用重写后保留base"/>★★★</para>
    ///  <para>-------------------------------------</para>
    /// </summary>
    public abstract void OnAppRun(bool IsRun);

    /// <summary>
    /// 当程序关闭时
    /// <para>-------------------------------------</para>
    /// <para>★★★<paramref name="框架使用重写后保留base"/>★★★</para>
    /// <para>-------------------------------------</para>
    /// </summary>
    public abstract void OnAppExit(bool IsRun);

    /// <summary>
    /// 全局异常捕获
    /// <paramref name="UnhandledExceptionEventArgs"/>
    /// <paramref name="DispatcherUnhandledExceptionEventArgs"/>
    /// <paramref name="UnobservedTaskExceptionEventArgs"/>
    /// </summary>
    /// <param name="source"></param>
    /// <param name="exception"></param>
    public virtual void GlobalException(string source, Exception exception)
    {

    }
    #endregion

    #region Module

    private List<Action<IServiceProvider>> OnModuleRunMethods = new List<Action<IServiceProvider>>();

    private void BuildModule()
    {
        //var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalModuleBootStartup))).ToArray();

        var types = VampirewalCoreContext.GetInstance().GetContext<Dictionary<string, IVampirewalModuleBootStartup>>("ModuleDic");

        foreach (var v in types)
        {
            var obj = v.Value;

            obj.BuildModuleBootStartUp(Collection);
            //obj.OnModuleRun(Services);

            Action<IServiceProvider> action = (Action<IServiceProvider>)Delegate.CreateDelegate(typeof(Action<IServiceProvider>), obj, obj.GetType().GetMethod("OnModuleRun"));

            OnModuleRunMethods.Add(action);
        }
    }

    private void SetBuildModuleServiceProvider()
    {
        foreach (var item in OnModuleRunMethods)
        {
            item.Invoke(Services);
        }
    }
    #endregion
}

/// <summary>
/// 引导启动异常
/// </summary>
[Serializable]
public class BootStartUpException : Exception
{
    /// <summary>
    /// 引导启动异常
    /// </summary>
    /// <param name="mes">错误消息</param>
    public BootStartUpException(string mes) : base(mes)
    {
    }
}